package tuplestore

import (
	"sync"
)

type TupleStore struct {
	mu             sync.RWMutex
	segments       []*Segment
	useCompression bool
}

type Segment struct {
	mu     sync.RWMutex
	Blocks []*Block
}

type Block struct {
	mu                sync.RWMutex
	MainStore         *MainStore
	DeltaStore        *DeltaStore
	CompressedColumns []*CompressedColumn
}

type MainStore struct {
	mu     sync.RWMutex
	tuples []*Tuple
}

type DeltaStore struct {
	mu   sync.RWMutex
	size int64
}

type Tuple struct {
	Data []byte
}

type CompressedColumn struct {
	EncodedData  []byte
	NullBitmap   []byte
	EncodingType EncodingType
	Dictionary   []interface{}
}

type EncodingType int

const (
	EncodingDictionary EncodingType = iota
)

// GetTotalSize 返回存储的总大小
func (ts *TupleStore) GetTotalSize() int64 {
	ts.mu.RLock()
	defer ts.mu.RUnlock()

	var totalSize int64
	for _, segment := range ts.segments {
		segment.mu.RLock()
		for _, block := range segment.Blocks {
			block.mu.RLock()

			if ts.useCompression && block.CompressedColumns != nil {
				// 计算压缩列的大小
				for _, col := range block.CompressedColumns {
					if col != nil {
						// 计算压缩列的总大小：
						// 1. 编码数据大小
						totalSize += int64(len(col.EncodedData))
						// 2. 空值位图大小
						totalSize += int64(len(col.NullBitmap))
						// 3. 字典大小（如果使用字典编码）
						if col.EncodingType == EncodingDictionary && col.Dictionary != nil {
							// 估算字典大小
							for _, v := range col.Dictionary {
								switch val := v.(type) {
								case string:
									totalSize += int64(len(val))
								case []byte:
									totalSize += int64(len(val))
								default:
									totalSize += 8 // 假设其他类型平均8字节
								}
							}
						}
					}
				}
			} else {
				// 如果没有压缩或压缩数据不可用，计算原始数据大小
				// 计算主存储大小
				block.MainStore.mu.RLock()
				for _, tuple := range block.MainStore.tuples {
					totalSize += int64(len(tuple.Data))
				}
				block.MainStore.mu.RUnlock()

				// 计算增量存储大小
				block.DeltaStore.mu.RLock()
				totalSize += block.DeltaStore.size
				block.DeltaStore.mu.RUnlock()
			}

			block.mu.RUnlock()
		}
		segment.mu.RUnlock()
	}
	return totalSize
}
